﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace JiaBao.Core.Infrastructure
{
    /// <summary>
    /// 应用程序查找器
    /// </summary>
    public class AppDomainTypeFinder : ITypeFinder
    {
        #region 字段

        /// <summary>
        ///  GetTypes 是否抛异常 
        /// </summary>
        private bool ignoreReflectionErrors = true;

        #endregion



        #region 属性

        /// <summary>
        /// 用于查找类型的应用程序域
        /// </summary>
        public virtual AppDomain App
        {
            get { return AppDomain.CurrentDomain; }
        }

        private bool _loadAppDomainAssemblies = true;
        /// <summary>
        /// 是否在加载类型时迭代应用程序域中已加载的程序集
        /// </summary>
        public bool LoadAppDomainAssemblies
        {
            get { return _loadAppDomainAssemblies; }
            set { _loadAppDomainAssemblies = value; }
        }


        private IList<string> _assemblyNames = new List<string>();
        /// <summary>
        /// AppDomain以外的追加文件
        /// </summary>
        public IList<string> AssemblyNames
        {
            get { return _assemblyNames; }
            set { _assemblyNames = value; }
        }

        private string _assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^AjaxControlToolkit|^Antlr3|^Autofac|^AutoMapper|^Castle|^ComponentArt|^CppCodeProvider|^DotNetOpenAuth|^EntityFramework|^EPPlus|^FluentValidation|^ImageResizer|^itextsharp|^log4net|^MaxMind|^MbUnit|^MiniProfiler|^Mono.Math|^MvcContrib|^Newtonsoft|^NHibernate|^nunit|^Org.Mentalis|^PerlRegex|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Rhino|^Telerik|^Iesi|^TestDriven|^TestFu|^UserAgentStringLibrary|^VJSharpCodeProvider|^WebActivator|^WebDev|^WebGrease";
        /// <summary>
        /// DLL名称 匹配规则
        /// </summary>
        public string AssemblySkipLoadingPattern
        {
            get { return _assemblySkipLoadingPattern; }
            set { _assemblySkipLoadingPattern = value; }
        }

        private string _assemblyRestrictToLoadingPattern = ".*";
        /// <summary>
        /// DLL类型 匹配规则
        /// </summary>
        public string AssemblyRestrictToLoadingPattern
        {
            get { return _assemblyRestrictToLoadingPattern; }
            set { _assemblyRestrictToLoadingPattern = value; }
        }


        #endregion

        #region 实现接口

        public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, bool onlyConcreteClasses = true)
        {
            return FindClassesOfType(assignTypeFrom, GetAssemblies(), onlyConcreteClasses);
        }
        public IEnumerable<Type> FindClassesOfType<T>(bool onlyConcreteClasses = true)
        {
            return FindClassesOfType(typeof(T), onlyConcreteClasses);
        }

        public IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
        {
            return FindClassesOfType(typeof(T), assemblies, onlyConcreteClasses);
        }

        public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
        {
            var result = new List<Type>();
            try
            {
                //便利提供程序集集合
                foreach (var a in assemblies)
                {
                    Type[] types = null;
                    //尝试读取程序集内types
                    try
                    {
                        types = a.GetTypes();
                    }
                    catch
                    {
                        //EF6不允许获取类型 会抛异常
                        if (!ignoreReflectionErrors)
                            throw;
                    }
                    if (types != null)
                    {
                        //遍历types 对比提供的查找类型
                        foreach (var t in types)
                        {
                            if (assignTypeFrom.IsAssignableFrom(t) || (assignTypeFrom.IsGenericTypeDefinition && DoesTypeImplementOpenGeneric(t, assignTypeFrom)))
                            {
                                //非接口
                                if (!t.IsInterface)
                                {
                                    if (onlyConcreteClasses)
                                    {
                                        //必实体类
                                        if (t.IsClass && !t.IsAbstract)
                                            result.Add(t);
                                    }
                                    else
                                    {
                                        result.Add(t);
                                    }
                                }
                            }
                        }
                    }

                }
            }
            catch (ReflectionTypeLoadException ex)
            {
                var msg = string.Empty;
                foreach (var e in ex.LoaderExceptions)
                    msg += e.Message + Environment.NewLine;

                var fail = new Exception(msg, ex);
                Debug.WriteLine(fail.Message, fail);

                throw fail;
            }

            return result;
        }


        /// <summary>
        /// 获取程序下所有程序集
        /// </summary>
        /// <returns></returns>
        public virtual IList<Assembly> GetAssemblies()
        {
            //已添加程序集
            var addedAssemblyNames = new List<string>();
            var assemblies = new List<Assembly>();

            //迭代程序已加载程序集
            if (LoadAppDomainAssemblies)
                AddAssembliesInAppDomain(addedAssemblyNames, assemblies);

            //追加
            AddConfiguredAssemblies(addedAssemblyNames, assemblies);

            return assemblies;

        }

        #endregion

        #region 内部方法

        /// <summary>
        /// 获取程序已加载所有符合匹配的程序集
        /// </summary>
        /// <param name="addedAssembliesName"></param>
        /// <param name="assemblies"></param>
        private void AddAssembliesInAppDomain(List<string> addedAssembliesName, List<Assembly> assemblies)
        {
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (Matches(assembly.FullName))
                {
                    assemblies.Add(assembly);
                    addedAssembliesName.Add(assembly.FullName);
                }
            }
        }



        #endregion

        /// <summary>
        /// 使用正则表达式 匹配程序集全名 (名称,文件类型匹配)
        /// </summary>
        /// <param name="assemblyFullName"></param>
        /// <returns></returns>
        public virtual bool Matches(string assemblyFullName)
        {
            return !Matches(assemblyFullName, AssemblySkipLoadingPattern)
                  && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern);
        }

        /// <summary>
        /// 使用正则表达式 匹配程序集全名
        /// </summary>
        /// <param name="assemblyFullName"></param>
        /// <param name="pattern"></param>
        /// <returns></returns>
        protected virtual bool Matches(string assemblyFullName, string pattern)
        {
            return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }


        /// <summary>
        /// 添加追加文件的程序集
        /// </summary>
        /// <param name="addedAssemblyNames"></param>
        /// <param name="assemblies"></param>
        protected virtual void AddConfiguredAssemblies(List<string> addedAssemblyNames, List<Assembly> assemblies)
        {
            foreach (string assemblyName in AssemblyNames)
            {
                Assembly assembly = Assembly.Load(assemblyName);
                if (!addedAssemblyNames.Contains(assembly.FullName))
                {
                    assemblies.Add(assembly);
                    addedAssemblyNames.Add(assembly.FullName);
                }
            }
        }

        /// <summary>
        /// 确保指定文件夹下的程序集已加载
        /// </summary>
        /// <param name="directoryPath"></param>
        protected virtual void LoadMatchingAssemblies(string directoryPath)
        {
            if (!Directory.Exists(directoryPath))
                return;

            //获取已加载程序集
            var loadedAssemblyNames = new List<string>();
            foreach (Assembly assembly in GetAssemblies())
            {
                loadedAssemblyNames.Add(assembly.FullName);
            }

            foreach (string dllPath in Directory.GetFiles(directoryPath, "*.dll"))
            {
                try
                {
                    var an = AssemblyName.GetAssemblyName(dllPath);
                    //名称匹配 且 没有加载
                    if (Matches(an.FullName) && !loadedAssemblyNames.Contains(an.FullName))
                        App.Load(an);
                }
                catch (BadImageFormatException ex)
                {

                    Trace.TraceError(ex.ToString());
                }
            }



        }

        /// <summary>
        /// 检测两个类型是否通用 (继承 实现 等关系)
        /// </summary>
        /// <param name="type"></param>
        /// <param name="openGeneric"></param>
        /// <returns></returns>
        protected virtual bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric)
        {
            try
            {
                var genericTypeDefinition = openGeneric.GetGenericTypeDefinition();
                foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null))
                {
                    if (!implementedInterface.IsGenericType)
                        continue;

                    var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
                    return isMatch;
                }
                return false;
            }
            catch
            {
                return false;
            }
        }


    }
}
